import Taro, { Component } from '@tarojs/taro'
import { ScrollView, Text, View } from "@tarojs/components"
import PropTypes from "prop-types"
import classNames from 'classnames'
import './index.scss'
import { formatStyle } from "../../utils";

/**
 * 基本 Tab 组件
 * @author zeng
 * @date   2020/3/26 11:31
 */
export default class GTabs extends Component {

  static options = {
    addGlobalClass: true
  }

  static propTypes = {
    data: PropTypes.oneOfType([ // 数据
      PropTypes.array,
      PropTypes.object
    ]),
    rootStyle: PropTypes.object, // 顶层容器的样式
    current: PropTypes.number, // 当前选中的 tab
    onClick: PropTypes.func, // 点击事件
    onClientRect: PropTypes.func, // 视图尺寸事件
    activeStyle: PropTypes.object, // 选中文案的样式
    tabStyle: PropTypes.object, // 默认文案样式
    lineStyle: PropTypes.object, // 下划线的样式
    renderLeft: PropTypes.element, // 渲染左边的元素
    scroll: PropTypes.bool, // 是否滚动
    direction: PropTypes.oneOf(['horizontal', 'vertical']), // 滚动方向，默认 'horizontal'
    label: PropTypes.string, // 显示文案的字段
    value: PropTypes.string, // 选中值的字段，为空时使用 index 作为值
  }

  tabRectList = []

  static defaultProps = {
    data: [
      { label: '推荐' },
      { label: '推荐推荐' },
      { label: '推荐' },
    ],
    rootStyle: {},
    current: 0,
    onClick: () => {
    },
    onClientRect: () => {
    },
    activeStyle: {},
    renderLeft: null,
    scroll: false,
    direction: 'horizontal',
    tabStyle: {},
    label: 'label'
  }

  state = {
    _scrollIntoView: '',
    activeLabelStyle: {},
    tabLabelStyle: {},
    lStyle: {}
  }

  _updateState = props => {
    if (!props.scroll) return
    const { current, value, data } = props
    this.setState({ _scrollIntoView: `tab-${Math.max(current - 1, 0)}` })
  }

  /**
   * 响应 tab 的尺寸
   * @author zeng
   * @date   2020/4/22 14:15
   */
  _updateTabRect = node => {
    node && node.boundingClientRect(this.props.onClientRect).exec()
  }

  // updateLineRect = () => {
  //   const query = Taro.createSelectorQuery().in(this.$scope)
  //   const className = `.tab__label-${this.props.direction}-active`
  //   const childrenNode = query.select(className)
  //   childrenNode && childrenNode.boundingClientRect(rect => {
  //     // this.tabRectList[index] = rect
  //     // console.log('rect -> ', rect)
  //   }).exec()
  // }

  /**
   * 获取 tabs 的位置，不要直接在 tab 上使用 ref，否则在 ref 函数里 setState 会造成无限更新
   * @param node
   */
  getLineRect = (node) => {
    const className = `.tab__label-${this.props.direction}`
    const childrenNode = node._selectorQuery.selectAll(className)
    childrenNode && childrenNode.boundingClientRect(rects => {
      this.tabRectList = rects.map(rect => ({ left: rect.left + 'px', width: rect.width + 'px' }))
      this.updateLineStyle()
    }).exec()
  }

  /**
   * 更新 line 的样式，从而修改它的 位置和宽度
   * @param {number} current 当前选中的索引
   */
  updateLineStyle = (current = this.props.current) => {
    const lineStyle = this.tabRectList[current]
    this.setState({ lStyle: lineStyle })
  }

  componentWillReceiveProps (nextProps, nextContext) {
    const isNotCurrent = nextProps.current !== this.props.current
    if (isNotCurrent) {
      this._updateState(nextProps)
      this.updateLineStyle(nextProps.current)
    }
  }

  componentWillMount () {
    const { activeStyle, tabStyle } = this.props
    Object.assign(this.state.activeLabelStyle,
      activeStyle.fontSize && { fontSize: activeStyle.fontSize },
      activeStyle.color && { color: activeStyle.color },
      activeStyle.fontWeight && { fontWeight: activeStyle.fontWeight },
    )
    Object.assign(this.state.tabLabelStyle,
      tabStyle.fontSize && { fontSize: tabStyle.fontSize },
      tabStyle.color && { color: tabStyle.color },
      tabStyle.fontWeight && { fontWeight: tabStyle.fontWeight },
    )
  }

  componentDidMount () {
    this._updateState(this.props)
  }

  render () {
    const {
      data,
      rootStyle,
      current,
      onClick,
      tabStyle, activeStyle, lineStyle,
      scroll, direction,
      label, value
    } = this.props
    const { _scrollIntoView, activeLabelStyle, tabLabelStyle, lStyle } = this.state
    const scrollX = direction === 'horizontal'
    const scrollY = direction === 'vertical'
    /* todo iphone 最后一个元素 margin-bottom 是 0，所以这块需要根据 手机平台 进行判断 */
    const _class = classNames(
      'flex-col',
      `tab-${direction}`,
      !scroll && `tab__no-scroll-${direction}`,
      scrollY && 'mb-40',
    )
    // tab 列表
    const tabList = data.map((tab, index) => {
      const isCurrent = +current === index
      return (
        <View
          onClick={() => onClick(index, tab)}
          className={_class}
          id={`tab-${index}`}
          key={index}
          style={Object.assign({}, tabStyle, isCurrent && activeStyle)}
        >
          <Text
            className={classNames(`tab__label-${direction}`, isCurrent && `tab__label-${direction}-active`)}
            style={Object.assign({}, formatStyle(tabLabelStyle), isCurrent && formatStyle(activeLabelStyle))}
          >
            {tab[label]}
          </Text>
          {
            scrollX && scroll && (
              <View className='tab__line-old'
                    style={{ ...formatStyle(lineStyle), backgroundColor: isCurrent ? '#DE2A2A' : 'transparent' }}
              />
            )
          }
        </View>
      )
    })
    return (
      <View
        className={`tabs flex-${scrollX ? 'row' : 'col'} tabs-${direction}`}
        style={rootStyle}
        ref={this._updateTabRect}
      >
        {this.props.renderLeft}
        {
          scroll ? (
            <ScrollView
              scrollIntoView={_scrollIntoView}
              scrollX={scrollX}
              scrollY={scrollY}
              scrollWithAnimation
              className={`tabs__scroll-${direction}`}
              ref={this.getLineRect}
            >
              {tabList}
            </ScrollView>
          ) : (
            <View className='tabs__no-scroll flex-row'>
              {tabList}
              <View className='tab__line'
                    style={{ ...lStyle, ...formatStyle(lineStyle) }}
              />
            </View>
          )
        }
        {this.props.children}
      </View>
    )
  }
}
